package com.mine.modules.sys.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mine.common.annotation.AutoLog;
import com.mine.common.config.BaseConfig;
import com.mine.common.constant.CacheConstant;
import com.mine.common.constant.CommonConstant;
import com.mine.common.domain.dto.LoginModel;
import com.mine.common.domain.vo.Result;
import com.mine.common.utils.*;
import com.mine.modules.sys.common.utils.RandImageUtil;
import com.mine.modules.sys.domain.dto.LoginDto;
import com.mine.modules.sys.entity.SysUser;
import com.mine.modules.sys.service.ILoginService;
import com.mine.modules.sys.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.LinkedHashMap;

@Slf4j
@RequiredArgsConstructor
@Service
public class LoginServiceImpl implements ILoginService {

    private final BaseConfig baseConfig;

    private final RedisUtil redisUtil;

    private final ISysUserService userService;

    private final static String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";


    @Override
    public Result<Object> login(LoginDto loginDto) throws Exception {
        log.info("登录请求参数sysLoginModel：{} ", loginDto);
        if (loginDto == null || StringUtils.isEmpty(loginDto.getUsername())
                || StringUtils.isEmpty(loginDto.getPassword())) {
            return Result.error("参数必填！");
        }
        Result<Object> result = new Result<Object>();
        String username = loginDto.getUsername();
        String password = loginDto.getPassword();

        System.out.println("登录参数：" + loginDto);

//        username = AesEncryptUtil.desEncrypt(username.replaceAll("%2B", "\\+")).trim();
//        password = AesEncryptUtil.desEncrypt(password.replaceAll("%2B", "\\+")).trim();

        //update-begin-author:taoyan date:20190828 for:校验验证码
        /*String captcha = sysLoginModel.getCaptcha();
        if (captcha == null) {
            result.error500("验证码无效");
            return result;
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        // 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
        String origin = lowerCaseCaptcha + sysLoginModel.getCheckKey() + baseConfig.getSignatureSecret();
        String realKey = Md5Util.md5Encode(origin, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            log.warn("验证码错误，key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
            result.error500("验证码错误");
            // 改成特殊的code 便于前端判断
            result.setCode(HttpStatus.PRECONDITION_FAILED.value());
            return result;
        }*/

        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = userService.getOne(queryWrapper);
        result = (Result<Object>) userService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            return result;
        }
        //用户登录信息
        userInfo(sysUser, result);
        redisUtil.del(CommonConstant.LOGIN_FAIL + username);
        LoginModel loginUser = new LoginModel();
        BeanUtils.copyProperties(sysUser, loginUser);
        return result;
    }

    @Override
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        String username = JwtUtil.getUsername(token);
        LoginModel sysUser = userService.getUserByName(username);
        if (sysUser != null) {
//            baseCommonService.addLog("用户名: "+sysUser.getRealname()+",退出成功！", CommonConstant.LOG_TYPE_1, null,sysUser);
            log.info(" 用户名:{},退出成功！ ", sysUser.getUsername());
            //清空用户登录Token缓存
            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getUsername());
            //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
            //调用shiro的logout
            SecurityUtils.getSubject().logout();
            return Result.ok("退出登录成功！");
        } else {
            return Result.error("Token无效!");
        }
    }

    @Override
    public Result<String> randomImage(HttpServletResponse response, String key) {
        Result<String> res = new Result<String>();
        try {
            //生成验证码
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            //存到redis中
            String lowerCaseCode = code.toLowerCase();

            // 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
            String realKey = Md5Util.md5Encode(lowerCaseCode, "utf-8");

            redisUtil.set(realKey, lowerCaseCode, 60);
            log.info("获取验证码，Redis key = {}，checkCode = {}", realKey, code);
            //返回前端
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            res.error500("获取验证码失败,请检查redis配置!");
            return res;
        }
        return res;
    }

    private Result<Object> userInfo(SysUser sysUser, Result<Object> result) {
        String username = sysUser.getUsername();
        String syspassword = sysUser.getPassword();
        // 获取用户部门信息
        JSONObject obj = new JSONObject(new LinkedHashMap<>());

        //1.生成token
        String token = JwtUtil.sign(username, syspassword);
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
        obj.put("token", token);
        sysUser.setPassword("");sysUser.setSalt("");
        obj.put("userInfo", sysUser);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

}
